﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.Client;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace SvnToTfs
{

  /// <summary>
  /// Manager of all TFS actions (connection,mapping,checkin,checkout,ect.)
  /// </summary>
  public class TFSModule
  {

    #region Private variables

    private Workspace _ws;

    #endregion

    #region Constructors

    public TFSModule()
    {

    }

    #endregion

    #region Properties

    public Workspace Workspace
    {
      get
      {
        return _ws;
      }
      set
      {
        _ws = value;
      }
    }

    #endregion
    
    #region Public methods

    /// <summary>
    /// Initiate the connection to the TFS Server and sets the workspace
    /// </summary>
    /// <param name="pcollection"></param>
    /// <param name="selectedProject"></param>
    /// <param name="folder"></param>
    /// <returns></returns>
    public bool InitiateTFS(string pcollection, string selectedProject, string branch, string folder)
    {
      //Get the wanted collection
      RegisteredProjectCollection RegisteredCollection;
      RegisteredCollection = RegisteredTfsConnections.GetProjectCollection(new Uri(pcollection));

      var projectCollection =
          TfsTeamProjectCollectionFactory.GetTeamProjectCollection(RegisteredCollection);

      try
      {
        //Get a reference to the source control
        var versionControl = (VersionControlServer)projectCollection.GetService(typeof(VersionControlServer));

        // Create a workspace
        String assemblyName = GetAssemblyName();
        String workspaceName = String.Format("{0}-{1}-{2}", new string[] {Environment.MachineName, 
                                                                                            assemblyName,
                                                                                            selectedProject});
        try
        {
          //Get the workspace if exist
          _ws = versionControl.GetWorkspace(workspaceName,
                                                  versionControl.AuthorizedUser);
        }
        catch (WorkspaceNotFoundException)
        {
          //Create the workspace if not exist
          _ws = versionControl.CreateWorkspace(workspaceName,
                                                     versionControl.AuthorizedUser);
        }
        //Set the working folder
        var serverFolder = String.Format("$/{0}{1}", versionControl.GetTeamProject(selectedProject).Name, branch);
        var workingFolder = new WorkingFolder(serverFolder, folder);

        try
        {
          // Create a workspace mapping
          _ws.CreateMapping(workingFolder);
        }
        catch (Exception)
        {

        }
        if (!_ws.HasReadPermission)
        {
          throw new SecurityException(
              String.Format(SvnToTfsResources.PermissionError,
                            versionControl.AuthorizedUser, serverFolder));
        }

        // Get the files from the repository
        _ws.Get();
      }
      catch (Exception)
      {
        return false;
      }

      return true;
    }

    /// <summary>
    /// Returns the list of Online Collections
    /// </summary>
    /// <returns></returns>
    public IEnumerable<string> GetOnlineCollections()
    {
      List<RegisteredProjectCollection> projectCollections = null;

      // Get all registered project collections (previously connected to from Team Explorer)
      projectCollections = new List<RegisteredProjectCollection>(
          (IEnumerable<RegisteredProjectCollection>)(RegisteredTfsConnections.GetProjectCollections()));

      // Filter down to only those collections that are currently on-line
      var onlineCollections =
          from collection in projectCollections
          where collection.Offline == false
          select collection;

      return onlineCollections.Select(x => x.Uri.ToString());
    }

    /// <summary>
    /// Returns the list of Team Projects associated with the collection
    /// </summary>
    /// <param name="collection"></param>
    /// <returns></returns>
    public IEnumerable<string> GetTeamProjects(string collection)
    {
      //Get the wanted collection
      RegisteredProjectCollection RegisteredCollection = RegisteredTfsConnections.GetProjectCollection(new Uri(collection));
      using (TfsTeamProjectCollection tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(RegisteredCollection))
      {
        //Get a reference to the source control
        var versionControl = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));

        //Get all TeamProjects from the specified collection
        var teamProjects = new List<TeamProject>((IEnumerable<TeamProject>)(versionControl.GetAllTeamProjects(false)));

        return teamProjects.Select(x => x.Name);
      }
    }

    public IEnumerable<string> GetBranches(string project, string collection)
    {
      List<string> branchList = new List<string>();
      branchList.Add("/");

      //Get the wanted collection
      RegisteredProjectCollection RegisteredCollection = RegisteredTfsConnections.GetProjectCollection(new Uri(collection));
      using (TfsTeamProjectCollection tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(RegisteredCollection))
      {
        //Get a reference to the source control
        var versionControl = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));

        //Get the wanted TeamProject
        TeamProject tproject = versionControl.GetTeamProject(project);

        //Get the branch structure from the selected TeamProject
        var branches = tproject.VersionControlServer.QueryRootBranchObjects(RecursionType.Full);

        Regex projectRoot = new Regex(string.Format("\\$/{0}/(.*)", project));

        foreach (BranchObject branch in branches)
        {
          if (projectRoot.IsMatch(branch.Properties.RootItem.Item))
            branchList.Add("/" + projectRoot.Replace(branch.Properties.RootItem.Item, "$1"));
        }

        return branchList;
      }
    }

    #endregion

    #region Private methods

    /// <summary>
    /// Get a friendly name of the current assembly to use in forming the name
    /// of the version control workspace to be created.
    /// </summary>
    /// <returns>Short/friendly name of assembly (e.g. BasicExample)</returns>
    private static String GetAssemblyName()
    {
      String assemblyName = AppDomain.CurrentDomain.FriendlyName;
      int dotPosition = assemblyName.IndexOf('.');

      if (dotPosition > 0)
      {
        assemblyName = assemblyName.Substring(0, dotPosition);
      }

      return assemblyName;
    }

    #endregion

  }
}
